/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package network;

import network.Layer;

/**
 *
 * @author Raise
 */
public class SoftmaxLayer extends Layer {

    private double[] lastOutput;

    public SoftmaxLayer(int inputSize) {
        this.inputSize = inputSize;
        this.outputSize = inputSize;
    }

    @Override
    public double[] forward(double[] input) {
        double[] output = new double[outputSize];
        double sum = 0;
        double max = Double.NEGATIVE_INFINITY;// 初始化为最小可能值

        // 步骤1：找到输入中的最大值（数值稳定技巧）
        for (double value : input) {
            if (value > max) {
                max = value;
            }
        }

        // 步骤2：计算指数（减去最大值防止溢出）
        for (int i = 0; i < inputSize; i++) {
            output[i] = Math.exp(input[i] - max);// 所有指数参数 ≤ 0
            sum += output[i];
        }

        // 步骤3：归一化（变成概率分布，总和为1）
        for (int i = 0; i < inputSize; i++) {
            output[i] /= sum;
        }

        lastOutput = output.clone();//保存输出概率
        return output;
    }

    @Override
    public double[] backward(double[] gradient, double learningRate) {
        return gradient;
    }

    //计算交叉熵损失（使用内部保存的lastOutput）
    public double crossEntropyLoss(int label) {
        //使用内部保存的lastOutput，不需要外部传入
        return -Math.log(lastOutput[label] + 1e-8);
    }

    public double[] crossEntropyGradient(int label) {
        double[] gradient = new double[outputSize];
        for (int i = 0; i < outputSize; i++) {
            // 核心公式：gradient[i] = 预测概率 - 真实标签
            gradient[i] = lastOutput[i] - (i == label ? 1 : 0);
        }
        return gradient;//算出这个梯度，就可以将梯度返回给全连接层了
    }


}
